using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Workflow;
using Microsoft.SharePoint.Administration;

namespace SharepointWorkflowStarter
{
    public partial class formMain : Form
    {
        private bool loggingOn = false;
        private System.IO.StreamWriter logWriter;
        private System.Collections.Hashtable workflowTemplateNames = new System.Collections.Hashtable();

        public formMain()
        {
            InitializeComponent();
        }

        #region "     Event Handlers     "
        private void checkBoxStopRunningInstances_CheckedChanged(object sender, EventArgs e)
        {
            startStopOptionsChanged();
        }

        private void checkBoxStartWorkflow_CheckedChanged(object sender, EventArgs e)
        {
            startStopOptionsChanged();
        }

        private void checkBoxAllSubSites_CheckedChanged(object sender, EventArgs e)
        {
            if (this.treeView1 == null || this.treeView1.SelectedNode == null || this.treeView1.SelectedNode.Tag == null)
            {
                return;
            }

            TreeNodeTag nodeTag = (TreeNodeTag)this.treeView1.SelectedNode.Tag;

            if (nodeTag.TreeNodeType == TreeNodeTag.TreeNodeTypes.WorkflowTemplate)
            {
                this.labelNodeType.Text = "Site and all subsites - " + this.treeView1.SelectedNode.Parent.Parent.Text;
            }
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            this.textBoxCustomAssociationData.Enabled = checkBoxUseCustomEventData.Checked;

            TreeNodeTag tag = (TreeNodeTag)this.treeView1.SelectedNode.Tag;

            if (this.checkBoxUseCustomEventData.Checked == false)
            {
                if (tag.TreeNodeType == TreeNodeTag.TreeNodeTypes.List)
                {
                    fillAssociationData(tag);
                }
            }
        }

        private void formMain_Load(object sender, EventArgs e)
        {
            this.treeView1.BackColor = SystemColors.InactiveBorder;
            getAppData();
        }

        private void formMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            saveAppData();
        }

        private void buttonGo_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;
            this.treeView1.BackColor = Color.White;
            this.toolStripStatusLabel1.Text = "Opening site " + this.textBoxSiteUrl.Text + "...";
            Application.DoEvents();
            using (SPSite site = new SPSite(this.textBoxSiteUrl.Text))
            {
                this.toolStripStatusLabel1.Text = "Opening web...";
                Application.DoEvents();
                using (SPWeb web = site.OpenWeb())
                {
                    this.toolStripStatusLabel1.Text = "Building tree...";
                    Application.DoEvents();

                    this.treeView1.Nodes.Clear();
                    this.treeView1.Nodes.Add(site.HostName, site.HostName, 0);
                    filltree(web, this.treeView1.Nodes[0]);
                    this.treeView1.Nodes[0].Expand();

                    if (this.treeView1.Nodes[0].Nodes.Count > 0)
                    {
                        this.treeView1.Nodes[0].Nodes[0].Expand();
                    }

                    panelMain.Enabled = true;
                    this.treeView1.Enabled = true;
                }
            }
            this.toolStripStatusLabel1.Text = "Ready";
            Application.DoEvents();
            this.Cursor = Cursors.Default;
        }

        private void buttonLogFileDialog_Click(object sender, EventArgs e)
        {            
            SaveFileDialog dialog = new SaveFileDialog();
            dialog.AddExtension = true;
            dialog.Filter = "Log Files | *.log";
            dialog.DefaultExt = "log";
            dialog.FileName = DateTime.Now.Year.ToString() + "-" + DateTime.Now.Month.ToString() + "-" + DateTime.Now.Day.ToString() + "_" + DateTime.Now.Hour.ToString() + "-" + DateTime.Now.Minute.ToString() + "-" + DateTime.Now.Second.ToString() + ".log";
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                this.labelLogPath.Text = dialog.FileName;
            }
        }

        private void buttonRunWorkflow_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;
            if (this.labelLogPath.Text != string.Empty)
            {
                loggingOn = true;
                logWriter = new System.IO.StreamWriter(this.labelLogPath.Text);
            }

            logWrite("Opening site ");

            TreeNodeTag selectedNodeTag = (TreeNodeTag)this.treeView1.SelectedNode.Tag;

            string siteUrl;
            siteUrl = selectedNodeTag.ItemUrl;

            using (SPSite site = new SPSite(siteUrl))
            {
                logWriteLine(site.Url + ": success");

                logWrite("Opening web: ");
                using (SPWeb web = site.OpenWeb())
                {
                    if (web.Exists)
                    {
                        logWriteLine("success");
                    }
                    else
                    {
                        logWriteLine("does not exist");
                        logWriteLine("End");
                        return;
                    }

                    if (selectedNodeTag.TreeNodeType == TreeNodeTag.TreeNodeTypes.List)
                    {
                        SPList docLib = web.GetList(selectedNodeTag.ItemUrl);
                        logWrite("Opening list " + this.treeView1.SelectedNode.Text + ": ");
                        logWriteLine("success");

                        iterateFolders(docLib.RootFolder);
                    }
                    else
                    {
                        iterateWebs(web, this.checkBoxAllSubSites.Checked);
                    }

                    logWriteLine("End");

                    if (loggingOn)
                    {
                        logWriter.Flush();
                        logWriter.Close();
                        logWriter.Dispose();
                    }
                }
            }

            this.Cursor = Cursors.Default;
            MessageBox.Show("Done", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);

#if !DEBUG
            try
            {
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Source + "\r\n" + ex.Message + " : " + ex.StackTrace);
            }
#endif
        }
        
        private void textBoxSiteUrl_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                buttonGo_Click(sender, e);
            }
        }

        private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            this.panelMainRight.Enabled = false;
            this.checkBoxAllSubSites.Enabled = false;
            this.textBoxCustomAssociationData.Text = string.Empty;
            this.buttonRunWorkflow.Enabled = false;
            startStopOptionsChanged();
            
            if (e.Node == null || e.Node.Tag == null)
            {
                this.labelActions.Text = string.Empty;
                this.labelWorkflowToRun.Text = string.Empty;
                this.labelNodeType.Text = string.Empty;
                return;
            }

            TreeNodeTag nodeTag = (TreeNodeTag)e.Node.Tag;
            string workflowName = workflowTemplateNames[nodeTag.WorkflowTemplateId].ToString();
            this.labelWorkflowToRun.Text = workflowName;

            if (nodeTag.TreeNodeType == TreeNodeTag.TreeNodeTypes.WorkflowTemplate)
            {
                this.checkBoxAllSubSites.Enabled = true;
                this.checkBoxAllSubSites.Checked = false;
                this.labelNodeType.Text = "Site - " + e.Node.Parent.Parent.Text;
                this.panelMainRight.Enabled = true;
            }
            else if (nodeTag.TreeNodeType == TreeNodeTag.TreeNodeTypes.List)
            {
                this.labelNodeType.Text = "List - " + e.Node.Text; ;
                this.panelMainRight.Enabled = true;
                fillAssociationData(nodeTag);
            }
            else if (nodeTag.TreeNodeType == TreeNodeTag.TreeNodeTypes.Web)
            {
                this.labelNodeType.Text = ":" + e.Node.Text;
                this.panelMainRight.Enabled = false;
            }
            else if (nodeTag.TreeNodeType == TreeNodeTag.TreeNodeTypes.File)
            {
                this.checkBoxAllSubSites.Enabled = false;

                this.labelNodeType.Text = "File - " + e.Node.Text; ;
                this.panelMainRight.Enabled = true;
                fillAssociationData(nodeTag);
            }
        }

        #endregion

        /// <summary>
        /// Gets the saved application data settings.
        /// </summary>
        private void getAppData()
        {
            this.textBoxSiteUrl.Text = Application.UserAppDataRegistry.GetValue("textBoxSiteUrl", "http://").ToString();
            string windowState = Application.UserAppDataRegistry.GetValue("WindowState", "").ToString();
            if (windowState.CompareTo(FormWindowState.Maximized.ToString()) == 0)
            {
                this.WindowState = FormWindowState.Maximized;
            }
            else
            {
                this.Width = int.Parse(Application.UserAppDataRegistry.GetValue("MainFormWidth", 600).ToString());
                this.Height = int.Parse(Application.UserAppDataRegistry.GetValue("MainFormHeight", 400).ToString());
            }
            
            this.treeView1.Width = int.Parse(Application.UserAppDataRegistry.GetValue("TreeViewWidth", 300).ToString());
        }

        /// <summary>
        /// Save application data settings
        /// </summary>
        private void saveAppData()
        {
            Application.UserAppDataRegistry.SetValue("textBoxSiteUrl", this.textBoxSiteUrl.Text);
            Application.UserAppDataRegistry.SetValue("MainFormWidth", this.Width);
            Application.UserAppDataRegistry.SetValue("MainFormHeight", this.Height);
            Application.UserAppDataRegistry.SetValue("TreeViewWidth", this.treeView1.Width);
            Application.UserAppDataRegistry.SetValue("WindowState", this.WindowState.ToString());
        }

        private void logWrite(string s)
        {
            if (loggingOn)
            {
                logWriter.Write(s);
            }
        }

        private void logWriteLine(string s)
        {
            if (loggingOn)
            {
                logWriter.WriteLine(s);
            }
        }


        private void iterateWebs(SPWeb web, bool iterateSubWebs)
        {
            List<Guid> listGuids = new List<Guid>();
          
            foreach (SPList list in web.Lists)
            {
                listGuids.Add(list.ID);
            }

            foreach (Guid listGuid in listGuids)
            {
                iterateFolders(web.Lists[listGuid].RootFolder);
            }

            if (iterateSubWebs)
            {
                List<Guid> subWebGuids = new List<Guid>();

                foreach (SPWeb subWeb in web.Webs)
                {
                    subWebGuids.Add(subWeb.ID);
                }

                foreach (Guid subWebGuid in subWebGuids)
                {
                    iterateWebs(web.Webs[subWebGuid], true);
                }
            }
        }

        private void iterateFolders(SPFolder folder)
        {
            SPDocumentLibrary docLib = null;

            logWrite("Opening list " + folder.Url + ": ");

            if (folder.ContainingDocumentLibrary != new Guid())
            {
                docLib = folder.ParentWeb.Lists[folder.ContainingDocumentLibrary] as SPDocumentLibrary;
                logWriteLine("");
            }
            else
            {
                logWriteLine("not a document library");
            }

            if (docLib != null && docLib.ItemCount > 0)
            {
                bool wfaFound = false;
                foreach (Microsoft.SharePoint.Workflow.SPWorkflowAssociation workflowAssociation in docLib.WorkflowAssociations)
                {
                    if (workflowAssociation.BaseTemplate != null && workflowAssociation.BaseTemplate.BaseId == ((TreeNodeTag)this.treeView1.SelectedNode.Tag).WorkflowTemplateId)
                    {
                        wfaFound = true;
                        logWriteLine("");

                        List<string> spFiles = new List<string>();

                        foreach (SPFile file in folder.Files)
                        {
                            TreeNodeTag currentNodeTag = (TreeNodeTag)this.treeView1.SelectedNode.Tag;

                            bool executeForFile = true;

                            if (currentNodeTag.TreeNodeType == TreeNodeTag.TreeNodeTypes.File)
                            {
                                executeForFile = (currentNodeTag.ItemUrl.ToLower().EndsWith(file.Url.ToLower()));
                            }

                            if (executeForFile)
                            {
                                spFiles.Add(file.Url);
                            }
                        }

                        if (spFiles.Count == 0)
                        {
                            logWriteLine("No files in " + folder.Url);
                        }

                        foreach (string spFile in spFiles)
                        {
                            SPFile file = folder.Files[spFile];
                            SPListItem li = file.Item;

                            if (li != null)
                            {
                                if (li.Workflows.Count > 0)
                                {
                                    if (this.checkBoxStopRunningInstances.Checked)
                                    {
                                        int i = 0;
                                        int totalCount = li.Workflows.Count;
                                        bool breakMe = false;
                                        do
                                        {
                                            Microsoft.SharePoint.Workflow.SPWorkflow workflow = li.Workflows[i];

                                            if (workflow.ParentAssociation.Name == workflowAssociation.Name)
                                            {
                                                breakMe = true;

                                                if (workflow.InternalState != Microsoft.SharePoint.Workflow.SPWorkflowState.Completed)
                                                {
                                                    logWriteLine("Workflow state is: " + workflow.InternalState.ToString());
                                                    logWriteLine(@"***Removing running workflows for file '" + li.Url + "'}");
                                                    folder.ParentWeb.Site.WorkflowManager.RemoveWorkflowFromListItem(workflow);
                                                    Application.DoEvents();
                                                    i--;
                                                    totalCount--;
                                                }
                                            }
                                            i++;

                                            if (i >= totalCount)
                                            {
                                                breakMe = true;
                                            }
                                        } while (!breakMe);
                                    }
                                }

                                if (this.checkBoxStartWorkflow.Checked)
                                {
                                    logWriteLine("List Item Level: " + li.Level.ToString());

                                    logWrite(@"***Starting workflow for file '" + li.Url + "': ");
                                    try
                                    {
                                        folder.ParentWeb.Site.WorkflowManager.StartWorkflow(li, workflowAssociation, workflowAssociation.AssociationData, true);
                                        logWriteLine("success");
                                    }
                                    catch (Exception ex)
                                    {
                                        logWriteLine("failed: " + ex.Message);
                                    }
                                }
                            }
                        }
                    }

                }


                if (!wfaFound)
                {
                    logWriteLine("worlflow assocation not found");
                }
            }
            else
            {
                //logWriteLine("");
            }

            foreach (SPFolder subfolder in folder.SubFolders)
            {
                iterateFolders(subfolder);
            }
        }

        private void filltree(SPWeb web, TreeNode node)
        {
            using (SPSite site = web.Site)
            {
                this.toolStripStatusLabel1.Text = web.Url;
                Application.DoEvents();

                TreeNode webNode = new TreeNode(web.Url);
                webNode.ImageIndex = 1;
                webNode.SelectedImageIndex = 1;
                node.Nodes.Add(webNode);
                this.Invalidate();
                Application.DoEvents();

                TreeNode nodeWorkflowTemplates = new TreeNode("Workflow Templates");
                nodeWorkflowTemplates.ImageIndex = 2;
                nodeWorkflowTemplates.SelectedImageIndex = 2;
                nodeWorkflowTemplates.Expand();
                webNode.Nodes.Add(nodeWorkflowTemplates);

                foreach (Microsoft.SharePoint.Workflow.SPWorkflowTemplate wfTemplate in web.WorkflowTemplates)
                {
                    if (!workflowTemplateNames.ContainsKey(wfTemplate.Id))
                    {
                        workflowTemplateNames.Add(wfTemplate.Id, wfTemplate.Name);
                    }
                    
                    TreeNode nodeWorkflowTemplate = new TreeNode(wfTemplate.Name);
                    nodeWorkflowTemplate.ImageIndex = 4;
                    nodeWorkflowTemplate.SelectedImageIndex = 4;
                    nodeWorkflowTemplate.Tag = new TreeNodeTag(web.Url, wfTemplate.Id, TreeNodeTag.TreeNodeTypes.WorkflowTemplate);
                    nodeWorkflowTemplates.Nodes.Add(nodeWorkflowTemplate);

                    int hasListCount = 0;
                    foreach (SPList list in web.Lists)
                    {
                        this.toolStripStatusLabel1.Text = web.Url + "/" + list.Title;
                        Application.DoEvents();
                        foreach (SPWorkflowAssociation workflowAssociation in list.WorkflowAssociations)
                        {
                            if (workflowAssociation.BaseTemplate == null)
                            {
                                continue;
                            }
                            if (workflowAssociation.BaseTemplate.BaseId == wfTemplate.Id)
                            {
                                hasListCount++;

                                TreeNode nodeWorkflowTemplateForList = new TreeNode(site.Url + list.RootFolder.ServerRelativeUrl);
                                nodeWorkflowTemplateForList.Tag = new TreeNodeTag(site.Url + list.RootFolder.ServerRelativeUrl, wfTemplate.Id, TreeNodeTag.TreeNodeTypes.List, list);
                                nodeWorkflowTemplateForList.ImageIndex = 3;
                                nodeWorkflowTemplateForList.SelectedImageIndex = 3;

                                if (!workflowAssociation.Enabled)
                                {
                                    nodeWorkflowTemplateForList.Text += " - Disabled (no new instances)";
                                }

                                nodeWorkflowTemplate.Nodes.Add(nodeWorkflowTemplateForList);

                                if (list.Folders.Count > 0)
                                {
                                    treeRecurseFolders(list.Folders[0].Folder.Item, nodeWorkflowTemplateForList, workflowAssociation);
                                }

                                treeAddFilesForFolder(list.RootFolder, nodeWorkflowTemplateForList, workflowAssociation, list);
                            }
                        }
                    }

                    nodeWorkflowTemplate.Text += " - " + hasListCount.ToString();
                }

                if (web.Webs.Count > 0)
                {
                    TreeNode subWebsNode = new TreeNode("Webs - " + web.Webs.Count.ToString());
                    subWebsNode.ImageIndex = 1;
                    subWebsNode.SelectedImageIndex = 1;
                    webNode.Nodes.Add(subWebsNode);

                    foreach (SPWeb subWeb in web.Webs)
                    {
                        filltree(subWeb, subWebsNode);
                    }
                }
            }
        }

        private void treeAddFilesForFolder(SPFolder folder, TreeNode parentNode, SPWorkflowAssociation workflowAssociation, SPList list)
        {
            foreach (SPFile file in folder.Files)
            {
                TreeNode nodeListItemsForWorkflowTemplateListFolder = new TreeNode(file.Name, 5, 5);

                TreeNodeTag tag = new TreeNodeTag(file.ParentFolder.ParentWeb.Url + "/" +  file.Url, workflowAssociation.BaseTemplate.Id, TreeNodeTag.TreeNodeTypes.File, list);
                nodeListItemsForWorkflowTemplateListFolder.Tag = tag;
                parentNode.Nodes.Add(nodeListItemsForWorkflowTemplateListFolder);
            }
        }

        private void treeRecurseFolders(SPListItem listItem, TreeNode parentNode, SPWorkflowAssociation workflowAssociation)
        {
            if (listItem == null)
            {
                return;
            }

            TreeNode nodeFolderForWorkflowTemplateList = new TreeNode(listItem.Name, 2, 2);
            parentNode.Nodes.Add(nodeFolderForWorkflowTemplateList);

            foreach (SPFolder folder in listItem.Folder.SubFolders)
            {
                treeRecurseFolders(folder.Item, nodeFolderForWorkflowTemplateList, workflowAssociation);
            }

            treeAddFilesForFolder(listItem.Folder, nodeFolderForWorkflowTemplateList, workflowAssociation, listItem.ParentList);
        }
        
        private void fillAssociationData(TreeNodeTag tag)
        {
            using (SPSite site = new SPSite(this.textBoxSiteUrl.Text))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    SPList list = tag.List;

                    foreach(SPWorkflowAssociation workflowAssociation in list.WorkflowAssociations)
                    {
                        if (workflowAssociation.BaseTemplate.Id == tag.WorkflowTemplateId)
                        {
                            this.textBoxCustomAssociationData.Text = workflowAssociation.AssociationData;
                            break;
                        }
                    }
                }
            }            
        }

        private void startStopOptionsChanged()
        {
            this.buttonRunWorkflow.Enabled = (this.checkBoxStopRunningInstances.Checked || this.checkBoxStartWorkflow.Checked);

            if (this.checkBoxStopRunningInstances.Checked && this.checkBoxStartWorkflow.Checked)
            {
                this.labelActions.Text = "Stop workflows, then start";
            }
            else if (!this.checkBoxStopRunningInstances.Checked && this.checkBoxStartWorkflow.Checked)
            {
                this.labelActions.Text = "Start workflows";
            }
            else if (this.checkBoxStopRunningInstances.Checked && !this.checkBoxStartWorkflow.Checked)
            {
                this.labelActions.Text = "Stop workflows";
            }
            else
            {
                this.labelActions.Text = string.Empty;
            }

            this.checkBoxUseCustomEventData.Enabled = this.checkBoxStartWorkflow.Checked;
            this.textBoxCustomAssociationData.Enabled = (this.checkBoxStartWorkflow.Checked && this.checkBoxUseCustomEventData.Checked);
        }

        private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
        {

        }
    }
}